1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.hiprenderer.backend.d3d.d3dvertex; 12 13 version(Windows): 14 version(DirectX): 15 import hip.util.string:toStringz; 16 import core.stdc.string; 17 import hip.util.conv:to; 18 import hip.error.handler; 19 import directx.d3d11; 20 import hip.util.system; 21 import hip.hiprenderer; 22 import hip.hiprenderer.backend.d3d.d3drenderer; 23 import hip.hiprenderer.shader; 24 import hip.hiprenderer.backend.d3d.d3dshader; 25 import hip.hiprenderer.vertex; 26 import hip.config.opts; 27 28 29 30 /** 31 * For reflecting OpenGL API, we create an accessor with the create functions, this is a locally 32 * managed array, but you're able to get it by using the private name, for flexibility. 33 */ 34 35 class Hip_D3D11_VertexBufferObject : IHipVertexBufferImpl 36 { 37 immutable D3D11_USAGE usage; 38 ID3D11Buffer buffer; 39 ulong size; 40 this(ulong size, HipBufferUsage usage) 41 { 42 this.size = size; 43 this.usage = getD3D11Usage(usage); 44 } 45 void bind(){} 46 void unbind() 47 { 48 _hip_d3d_context.IASetVertexBuffers(0, 0, null, null, null); 49 HipRenderer.exitOnError(); 50 } 51 52 53 bool started = false; 54 void createBuffer(const void[] data) 55 { 56 started = true; 57 this.size = data.length; 58 D3D11_BUFFER_DESC bd; 59 bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; 60 bd.Usage = usage; 61 bd.CPUAccessFlags = getD3D11_CPUUsage(usage); 62 bd.MiscFlags = 0u; 63 bd.ByteWidth = cast(uint)size; 64 bd.StructureByteStride = 0; 65 66 D3D11_SUBRESOURCE_DATA sd; 67 sd.pSysMem = cast(void*)data.ptr; 68 69 //TODO: Check failure 70 71 d3dCall(() => _hip_d3d_device.CreateBuffer(&bd, &sd, &buffer)); 72 73 HipRenderer.exitOnError(); 74 } 75 void setData(const(void)[] data) 76 { 77 if(data == null || data.length == 0) 78 return; 79 createBuffer(data); 80 } 81 void updateData(int offset, const (void)[] data) 82 { 83 if(data.length + offset > this.size) 84 { 85 ErrorHandler.assertExit(false, 86 "Tried to set data with size "~to!string(size)~" and offset "~to!string(offset)~ 87 "for vertex buffer with size "~to!string(this.size)); 88 } 89 90 D3D11_MAPPED_SUBRESOURCE resource; 91 _hip_d3d_context.Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); 92 memcpy(resource.pData+offset, data.ptr, data.length); 93 _hip_d3d_context.Unmap(buffer, 0); 94 HipRenderer.exitOnError(); 95 } 96 } 97 class Hip_D3D11_IndexBufferObject : IHipIndexBufferImpl 98 { 99 immutable D3D11_USAGE usage; 100 ID3D11Buffer buffer; 101 uint count; 102 ulong size; 103 this(uint count, HipBufferUsage usage) 104 { 105 this.size = count*index_t.sizeof; 106 this.count = count; 107 this.usage = getD3D11Usage(usage); 108 } 109 protected void createBuffer(uint count, void* data) 110 { 111 this.size = count*index_t.sizeof; 112 D3D11_BUFFER_DESC bd; 113 bd.BindFlags = D3D11_BIND_INDEX_BUFFER; 114 bd.Usage = usage; 115 bd.CPUAccessFlags = getD3D11_CPUUsage(usage); 116 bd.MiscFlags = 0u; 117 bd.ByteWidth = cast(uint)this.size; 118 bd.StructureByteStride = 0; 119 D3D11_SUBRESOURCE_DATA sd; 120 sd.pSysMem = cast(void*)data; 121 //TODO: Check failure 122 _hip_d3d_device.CreateBuffer(&bd, &sd, &buffer); 123 } 124 void bind() 125 { 126 static if(is(index_t == uint)) 127 _hip_d3d_context.IASetIndexBuffer(buffer, DXGI_FORMAT_R32_UINT, 0); 128 else 129 _hip_d3d_context.IASetIndexBuffer(buffer, DXGI_FORMAT_R16_UINT, 0); 130 } 131 void unbind() 132 { 133 static if(is(index_t == uint)) 134 _hip_d3d_context.IASetIndexBuffer(null, DXGI_FORMAT_R32_UINT, 0); 135 else 136 _hip_d3d_context.IASetIndexBuffer(null, DXGI_FORMAT_R16_UINT, 0); 137 } 138 139 /** 140 * If the count is 0, it means that it should create the vertex buffero 141 * with its creation size 142 */ 143 void setData(const index_t[] data) 144 { 145 if(count == 0) 146 { 147 createBuffer(this.count, cast(void*)data.ptr); 148 return; 149 } 150 createBuffer(cast(index_t)data.length, cast(void*)data.ptr); 151 } 152 void updateData(int offset, const index_t[] data) 153 { 154 if(data.length*index_t.sizeof + offset >= this.size) 155 { 156 ErrorHandler.assertExit(false, 157 "Tried to set data with size "~to!string(data.length*index_t.sizeof)~" and offset "~to!string(offset)~ 158 "for vertex buffer with size "~to!string(this.size)); 159 } 160 D3D11_MAPPED_SUBRESOURCE resource; 161 _hip_d3d_context.Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); 162 memcpy(resource.pData+offset, data.ptr, data.length*index_t.sizeof); 163 _hip_d3d_context.Unmap(buffer, 0); 164 HipRenderer.exitOnError(); 165 } 166 } 167 168 class Hip_D3D11_VertexArrayObject : IHipVertexArrayImpl 169 { 170 ID3D11InputLayout inputLayout; 171 D3D11_INPUT_ELEMENT_DESC[] descs; 172 uint stride; 173 this(){} 174 void bind(IHipVertexBufferImpl vbo, IHipIndexBufferImpl ebo) 175 { 176 static uint offset = 0; 177 /** It must return silently to support opengl VAO binding*/ 178 if(inputLayout is null) 179 return; 180 Hip_D3D11_VertexBufferObject v = cast(Hip_D3D11_VertexBufferObject)vbo; 181 _hip_d3d_context.IASetInputLayout(inputLayout); 182 _hip_d3d_context.IASetVertexBuffers(0u, 1u, &v.buffer, &stride, &offset); 183 ebo.bind(); 184 HipRenderer.exitOnError(); 185 } 186 void unbind(IHipVertexBufferImpl vbo, IHipIndexBufferImpl ebo) 187 { 188 if(vbo is null) 189 return; 190 vbo.unbind(); 191 ebo.unbind(); 192 _hip_d3d_context.IASetInputLayout(null); 193 HipRenderer.exitOnError(); 194 } 195 void setAttributeInfo(ref HipVertexAttributeInfo info, uint stride) 196 { 197 this.stride = stride; 198 D3D11_INPUT_ELEMENT_DESC desc; 199 desc.SemanticName = info.name.toStringz; 200 desc.SemanticIndex = 0; 201 // desc.SemanticIndex = info.index; 202 desc.Format = _hip_d3d_getFormatFromInfo(info); 203 desc.InputSlot = 0; 204 desc.AlignedByteOffset = info.offset; 205 desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; 206 desc.InstanceDataStepRate = 0; 207 descs~= desc; 208 } 209 void createInputLayout(Shader s) 210 { 211 if(ErrorHandler.assertErrorMessage(s !is null, "D3D11 VAO Error", "Error at creating input layout")) 212 return; 213 Hip_D3D11_VertexShader vs = cast(Hip_D3D11_VertexShader)s.vertexShader; 214 215 216 _hip_d3d_device.CreateInputLayout(descs.ptr, cast(uint)descs.length, 217 vs.shader.GetBufferPointer(), vs.shader.GetBufferSize(), &inputLayout); 218 HipRenderer.exitOnError(); 219 } 220 } 221 222 private int getD3D11Usage(HipBufferUsage usage) 223 { 224 switch(usage) with(HipBufferUsage) 225 { 226 default: 227 case DEFAULT: 228 return D3D11_USAGE_DEFAULT; 229 case DYNAMIC: 230 return D3D11_USAGE_DYNAMIC; 231 case STATIC: 232 return D3D11_USAGE_IMMUTABLE; 233 } 234 } 235 236 private int getD3D11_CPUUsage(D3D11_USAGE usage) 237 { 238 switch(usage) 239 { 240 default: 241 case D3D11_USAGE_DEFAULT: 242 return D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; 243 case D3D11_USAGE_DYNAMIC: 244 return D3D11_CPU_ACCESS_WRITE; 245 case D3D11_USAGE_IMMUTABLE: 246 return 0; 247 } 248 } 249 250 private DXGI_FORMAT _hip_d3d_getFormatFromInfo(ref HipVertexAttributeInfo info) 251 { 252 DXGI_FORMAT ret; 253 switch(info.valueType) 254 { 255 case HipAttributeType.Rgba32: 256 return DXGI_FORMAT_R8G8B8A8_UNORM; 257 case HipAttributeType.Float: 258 switch(info.count) 259 { 260 case 1: ret = DXGI_FORMAT_R32_FLOAT; break; 261 case 2: ret = DXGI_FORMAT_R32G32_FLOAT; break; 262 case 3: ret = DXGI_FORMAT_R32G32B32_FLOAT; break; 263 case 4: ret = DXGI_FORMAT_R32G32B32A32_FLOAT; break; 264 default: 265 ErrorHandler.showErrorMessage("DXGI Format Error", 266 "Unknown format type from float with length " ~ to!string(info.count)); 267 } 268 break; 269 case HipAttributeType.Uint: 270 switch(info.count) 271 { 272 case 1: ret = DXGI_FORMAT_R32_UINT; break; 273 default: 274 ErrorHandler.showErrorMessage("DXGI Format Error", 275 "Unknown format type from uint with length " ~ to!string(info.count)); 276 } 277 break; 278 case HipAttributeType.Bool: 279 case HipAttributeType.Int: 280 switch(info.count) 281 { 282 case 1: ret = DXGI_FORMAT_R32_SINT; break; 283 case 2: ret = DXGI_FORMAT_R32G32_SINT; break; 284 case 3: ret = DXGI_FORMAT_R32G32B32_SINT; break; 285 case 4: ret = DXGI_FORMAT_R32G32B32A32_SINT; break; 286 default: 287 ErrorHandler.showErrorMessage("DXGI Format Error", 288 "Unknown format type from int/bool with length " ~ to!string(info.count)); 289 } 290 break; 291 default: 292 ErrorHandler.showErrorMessage("DXGI Format Error", "Unknown format type from info"); 293 break; 294 } 295 return ret; 296 }